import { Injectable, UnauthorizedException, BadRequestException, InternalServerErrorException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../user/entities/user.entity';
import { SmsCode } from '../sms/entities/sms-code.entity';
import { CryptoUtil } from '../../utils/crypto.util';
import { OperationLoggerService } from '../../services/operation-logger.service';
import { JWT_SECRET } from '../../config/jwt.config';
import {
  LoginDto,
  PhoneLoginDto,
  SmsLoginDto,
  RegisterDto,
  ResetPasswordDto,
  SendSmsDto,
  SmsType,
} from './dto/auth.dto';
import { SmsService } from '../sms/sms.service';
import { TencentImService } from '../message/tencent-im.service';

@Injectable()
export class AuthService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    @InjectRepository(SmsCode)
    private readonly smsCodeRepository: Repository<SmsCode>,
    private readonly jwtService: JwtService,
    private readonly smsService: SmsService, // 注入 SmsService
    private readonly logger: OperationLoggerService,
    private readonly tencentImService: TencentImService,
  ) {}

  async generateToken(user: User) {
    try {
      // 确保用户对象有有效的 username
      const username = user.username || user.phone || `user_${user.id}`;
      
      const payload = { 
        sub: user.id, 
        id: user.id, // 添加 id 字段，确保 JWT 中包含用户 ID
        username: username,
        phone: user.phone
      };
      
      console.log('生成 token 的 payload:', payload);
      
      // 确保 JWT_SECRET 是有效的
      if (!JWT_SECRET || JWT_SECRET === 'your-super-secret-key-2024') {
        console.warn('警告：使用默认的 JWT 密钥，建议在生产环境中更改');
      }
      
      const token = this.jwtService.sign(payload);
      console.log('生成的 token 前10个字符:', token.substring(0, 10) + '...');
      
      return token;
    } catch (error) {
      this.logger.logError('generateToken', error);
      throw new InternalServerErrorException('生成令牌时发生错误');
    }
  }

  private async validateSmsCode(phone: string, code: string, type: SmsType): Promise<boolean> {
    const smsCode = await this.smsCodeRepository.findOne({
      where: {
        phone,
        code,
        type,
        isUsed: false,
      },
      order: { createdAt: 'DESC' },
    });

    if (!smsCode) {
      return false;
    }

    if (new Date() > smsCode.expireAt) {
      return false;
    }

    smsCode.isUsed = true;
    await this.smsCodeRepository.save(smsCode);
    return true;
  }

  async passwordLogin(loginDto: LoginDto, ip: string) {
    try {
      const user = await this.userRepository.findOne({
        where: [
          { username: loginDto.username },
          { phone: loginDto.username },
        ],
      });

      if (!user) {
        this.logger.logAuthOperation('password_login', loginDto.username, false, 'User not found');
        // 改为 400 Bad Request，而不是 401 Unauthorized
        throw new BadRequestException('用户名或密码错误');
      }

      const isPasswordValid = await CryptoUtil.compare(
        loginDto.password,
        user.password,
      );

      if (!isPasswordValid) {
        this.logger.logAuthOperation('password_login', loginDto.username, false, 'Invalid password');
        // 改为 400 Bad Request，而不是 401 Unauthorized
        throw new BadRequestException('用户名或密码错误');
      }

      // 更新登录信息
      user.lastLoginAt = new Date();
      user.lastLoginIp = ip;
      await this.userRepository.save(user);

      const token = await this.generateToken(user);
      this.logger.logAuthOperation('password_login', loginDto.username, true);
      
      // 直接返回 token，让拦截器包装响应格式
      return { token };
    } catch (error) {
      this.logger.logError('passwordLogin', error);
      if (error instanceof BadRequestException) {
        throw error;
      }
      throw new InternalServerErrorException('登录过程中发生错误');
    }
  }

  async phoneLogin(phoneLoginDto: PhoneLoginDto, ip: string) {
    const user = await this.userRepository.findOne({
      where: { phone: phoneLoginDto.phone },
    });

    if (!user) {
      throw new UnauthorizedException('手机号未注册');
    }

    const isPasswordValid = await CryptoUtil.compare(
      phoneLoginDto.password,
      user.password,
    );

    if (!isPasswordValid) {
      throw new UnauthorizedException('密码错误');
    }

    user.lastLoginAt = new Date();
    user.lastLoginIp = ip;
    await this.userRepository.save(user);

    return this.generateToken(user);
  }

  async smsLogin(smsLoginDto: SmsLoginDto, ip: string) {
    const isValid = await this.validateSmsCode(
      smsLoginDto.phone,
      smsLoginDto.code,
      SmsType.LOGIN,
    );

    if (!isValid) {
      throw new UnauthorizedException('验证码无效或已过期');
    }

    let user = await this.userRepository.findOne({
      where: { phone: smsLoginDto.phone },
    });

    if (!user) {
      // 如果用户不存在，自动注册
      user = new User();
      user.phone = smsLoginDto.phone;
      user.isPhoneVerified = true;
      user = await this.userRepository.save(user);
    }

    user.lastLoginAt = new Date();
    user.lastLoginIp = ip;
    await this.userRepository.save(user);

    return this.generateToken(user);
  }

  async register(registerDto: RegisterDto) {
    const isValid = await this.validateSmsCode(
      registerDto.phone,
      registerDto.code,
      SmsType.REGISTER,
    );

    if (!isValid) {
      throw new BadRequestException('验证码无效或已过期');
    }

    const existingUser = await this.userRepository.findOne({
      where: { phone: registerDto.phone },
    });

    if (existingUser) {
      throw new BadRequestException('手机号已注册');
    }

    // 确保密码不为空
    if (!registerDto.password || registerDto.password.trim() === '') {
      throw new BadRequestException('密码不能为空');
    }

    const user = new User();
    user.phone = registerDto.phone;
    // 生成用户名
    user.username = `user_${Date.now()}`;
    // 生成昵称
    user.nickname = `用户${Math.floor(Math.random() * 10000)}`;
    // 使用 CryptoUtil 加密密码
    user.password = await CryptoUtil.hash(registerDto.password);
    user.isPhoneVerified = true;

    try {
      await this.userRepository.save(user);
      
      // 注册成功后，尝试将用户导入到腾讯云IM
      try {
        await this.tencentImService.importUserToTencentIM(user.id);
      } catch (imError) {
        // 记录错误但不影响注册流程
        console.error(`导入用户到腾讯云IM失败: ${imError.message}`);
      }
      
      return {
        message: '注册成功',
      };
    } catch (error) {
      this.logger.logError(`注册失败: ${error.message}`, error.stack);
      throw new InternalServerErrorException('注册失败，请稍后再试');
    }
  }

  async resetPassword(resetPasswordDto: ResetPasswordDto) {
    const isValid = await this.validateSmsCode(
      resetPasswordDto.phone,
      resetPasswordDto.code,
      SmsType.RESET_PASSWORD,
    );

    if (!isValid) {
      throw new BadRequestException('验证码无效或已过期');
    }

    const user = await this.userRepository.findOne({
      where: { phone: resetPasswordDto.phone },
    });

    if (!user) {
      throw new BadRequestException('手机号未注册');
    }

    user.password = await CryptoUtil.hash(resetPasswordDto.password);
    await this.userRepository.save(user);

    return {
      message: '密码重置成功',
    };
  }

  async sendSms(sendSmsDto: SendSmsDto) {
    try {
      // 检查是否有未过期的验证码
      const existingCode = await this.smsCodeRepository.findOne({
        where: {
          phone: sendSmsDto.phone,
          type: sendSmsDto.type,
          isUsed: false,
        },
        order: { createdAt: 'DESC' },
      });

      if (existingCode && new Date() < existingCode.expireAt) {
        throw new BadRequestException('验证码已发送，请稍后再试');
      }

      // 使用 SmsService 发送验证码
      const code = await this.smsService.sendCode(sendSmsDto.phone);
      
      // 保存验证码记录
      const smsCode = new SmsCode();
      smsCode.phone = sendSmsDto.phone;
      smsCode.code = code;
      smsCode.type = sendSmsDto.type;
      smsCode.expireAt = new Date(Date.now() + 5 * 60 * 1000); // 5分钟有效期

      await this.smsCodeRepository.save(smsCode);

      return code
    } catch (error) {
      console.error('发送验证码失败:', error);
      throw new InternalServerErrorException(error);
    }
  }

  async logout(userId: number): Promise<void> {
    try {
      // 这里可以添加一些逻辑，比如将 token 加入黑名单
      // 或者记录用户退出登录的时间
      console.log('用户退出登录, userId:', userId);
      
      // 如果有需要，可以更新用户的最后登出时间
      // 但由于 User 实体中没有 lastLogoutAt 字段，我们不设置它
      const user = await this.userRepository.findOne({ where: { id: userId } });
      if (user) {
        // 如果需要记录登出时间，应该先在 User 实体中添加 lastLogoutAt 字段
        // user.lastLogoutAt = new Date();
        // await this.userRepository.save(user);
        
        // 暂时只记录日志
        this.logger.logAuthOperation('logout', user.username, true);
      }
    } catch (error) {
      this.logger.logError('logout', error);
      throw new InternalServerErrorException('退出登录时发生错误');
    }
  }
}



